package com.higgins.server.knowledge;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.higgins.client.knowledge.KnowledgeItemDTO;
import com.higgins.client.knowledge.KnowledgeService;
import com.higgins.client.projectmanagement.HistoryItemDTO;
import com.higgins.client.projectmanagement.ProjectItemDTO;
import com.higgins.client.projectmanagement.ProjectService;
import com.higgins.server.DateUtility;
import com.higgins.server.projectmanagement.datamodel.ProjectItem;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class KnowledgeServiceImpl extends RemoteServiceServlet implements KnowledgeService {
	private static final Logger log = Logger.getLogger(KnowledgeServiceImpl.class.getName());
	private EntityManagerFactory emfInstance = Persistence
			.createEntityManagerFactory("com.higgins.server.jpa");

	public KnowledgeServiceImpl()	{		 
	}
	public void doGet(HttpServletRequest req, HttpServletResponse resp)	throws IOException	{
		log.info("Ping Received!");
	}
	@Override
	public List<KnowledgeItemDTO> retrieveTopLevelKnowledgeItems()
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		List<KnowledgeItemDTO> dtoList = new ArrayList<KnowledgeItemDTO>();
		Query query = entityManager.createQuery( "from KnowledgeItem s where s.topLevel = :arg1 order by item asc");
		query.setParameter("arg1", true);
		List<KnowledgeItem> results = query.getResultList();
		System.out.println("Size of list = " + results.size());
		for (KnowledgeItem result:results)	{
			KnowledgeItemDTO dto = result.toDTO();
			dtoList.add(dto);
		}
		return dtoList;
	}

	
	@Override
	public List<KnowledgeItemDTO> retrieveKnowledgeItems(String level, Long parentId)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		List<KnowledgeItemDTO> dtoList = new ArrayList<KnowledgeItemDTO>();
		if (parentId == null)	{
			Query query = null;
			if (level == null)	{
				query = entityManager.createQuery( "from KnowledgeItem s where s.parentId IS NULL order by id asc");
			} else {
				query = entityManager.createQuery( "from KnowledgeItem s where s.parentId IS NULL and s.item = :levelParam order by id asc");
				query.setParameter("levelParam", level);
			}
			List<KnowledgeItem> results = query.getResultList();
			System.out.println("Size of list = " + results.size());
			for (KnowledgeItem result:results)	{
				KnowledgeItemDTO dto = result.toDTO();
				dtoList.add(dto);
			}

		
		} else {
			Query query = entityManager.createQuery( "from KnowledgeItem s where s.parentId = :arg1 order by id asc");
			query.setParameter("arg1", parentId);
			List<KnowledgeItem> results = query.getResultList();
			System.out.println("Size of list = " + results.size());
			for (KnowledgeItem result:results)	{
				KnowledgeItemDTO dto = result.toDTO();
				dtoList.add(dto);
			}
		}
		entityManager.close();	
		return dtoList;
	}

	@Override
	public List<KnowledgeItemDTO> retrievePreviousKnowledgeItems(Long parentId)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		List<KnowledgeItemDTO> dtoList = new ArrayList<KnowledgeItemDTO>();
		if (parentId == null)	{
			return null;
		} else {
			KnowledgeItem parentItem = getKnowledgeItemById(entityManager, parentId);
			Query query = entityManager.createQuery( "from KnowledgeItem s where s.parentId = :arg1 order by id asc");
			query.setParameter("arg1", parentItem.getParentId());
			List<KnowledgeItem> results = query.getResultList();
			System.out.println("Size of list = " + results.size());
			for (KnowledgeItem result:results)	{
				KnowledgeItemDTO dto = result.toDTO();
				dtoList.add(dto);
			}
		}
		entityManager.close();	
		return dtoList;
	}	
	
	@Override
	public List<KnowledgeItemDTO> retrieveRandomKnowledgeItemRelationships(
			Long parentId) throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		List<KnowledgeItemDTO> dtoList = new ArrayList<KnowledgeItemDTO>();
		if (parentId == null)	{
			Query query = entityManager.createQuery( "from KnowledgeItem k where k.parentId in (select s.id from KnowledgeItem s where s.relationship = :arg1) order by id asc");
			query.setParameter("arg1", true);
			List<KnowledgeItem> results = query.getResultList();
			System.out.println("Size of list = " + results.size());
			for (KnowledgeItem result:results)	{
				KnowledgeItemDTO dto = result.toDTO();
				dtoList.add(dto);
			}
		} else { // MORE COMPLEX!!!!!! (RECURSIVE DOWN THE CHAIN FROM THE PARENT ID
//			Query query = entityManager.createQuery( "from KnowledgeItem k where k.parentId in (select s.id from KnowledgeItem s where s.parentId = :arg1 and s.relationship = :arg2) order by id asc");
			List<KnowledgeItem> fullList = new ArrayList<KnowledgeItem>();
			List<Long> parentIds = new ArrayList<Long>();
			List<Long> fullListOfItemIds = new ArrayList<Long>();
			parentIds.add(parentId);
			while (parentIds.size()>0)	{
				Query query = entityManager.createQuery( "select s.id from KnowledgeItem s where s.parentId in (:arg1) ");
				query.setParameter("arg1", parentIds);
				List<Long> results = query.getResultList();
				fullListOfItemIds.addAll(results);
				parentIds = results;
			}
			
			Query query = entityManager.createQuery( "from KnowledgeItem s where s.id in (:arg1) and s.relationship = :arg2 order by id asc");
			query.setParameter("arg1", fullListOfItemIds);
			query.setParameter("arg2", true);
			List<KnowledgeItem> results = query.getResultList();
			System.out.println("Size of list = " + results.size());
			for (KnowledgeItem result:results)	{
				KnowledgeItemDTO dto = result.toDTO();
				dtoList.add(dto);
			}
		}
		entityManager.close();	
		return dtoList;	}
/*
	private List<ProjectItem> retrievePersistentProjectItems(Long parentId)	{
		EntityManager entityManager = emfInstance.createEntityManager();
		List<ProjectItemDTO> dtoList = new ArrayList<ProjectItemDTO>();
	
		Query query = entityManager.createQuery( "from ProjectItem s where s.parentId = :arg1 order by priority asc");
		query.setParameter("arg1", parentId);
		List<ProjectItem> children = query.getResultList();
		entityManager.close();		
		return children;
	}		*/
	@Override
	public KnowledgeItemDTO getKnowledgeItemById(Long id)	{
		EntityManager entityManager = emfInstance.createEntityManager();
		KnowledgeItem item = getKnowledgeItemById(entityManager, id);
		entityManager.close();
		return item.toDTO();
	}
	private KnowledgeItem getKnowledgeItemById(EntityManager entityManager, Long id)	{
		List<ProjectItemDTO> dtoList = new ArrayList<ProjectItemDTO>();
	
		Query query = entityManager.createQuery( "from KnowledgeItem s where s.id = :arg1 order by id asc");
		query.setParameter("arg1", id);
		List<KnowledgeItem> children = query.getResultList();
		if (children.size() > 0)
			return children.get(0);
		else 
			return null;
	}	

	@Override
	public List<Long> retrieveParentIds(Long childId)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		Long parentId = new Long(0);
		List<Long> parentIds = new ArrayList<Long>();
		if (childId!=null)	{
			parentId = childId;
			while (parentId!=null)	{
				KnowledgeItem item = null;
				try	{
					item = getKnowledgeItemById(entityManager, parentId);
					parentIds.add(parentId);
					parentId = item.getParentId();
				} catch (Exception e)	{
					parentId = null;
				}
			}
		}
		entityManager.close();
		return parentIds;
	}
	

	@Override
	public Long insetKnowledgeItem(KnowledgeItemDTO item)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		KnowledgeItem parent = new KnowledgeItem();
		parent.update(item);
		entityManager.getTransaction().begin();
		entityManager.persist(parent);
		entityManager.getTransaction().commit();
		entityManager.close();
		return parent.getId();
	}

	@Override
	public Long updateKnowledgeItem(KnowledgeItemDTO itemDTO)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		if (itemDTO.getId() != null)	{	
			entityManager.getTransaction().begin();
			KnowledgeItem item = getKnowledgeItemById(entityManager, itemDTO.getId());
			item.update(itemDTO);
			entityManager.persist(item);
			entityManager.getTransaction().commit();
			entityManager.close();
			return item.getId();
		} else {
			entityManager.getTransaction().begin();
			KnowledgeItem item = new KnowledgeItem();
			item.update(itemDTO);
			entityManager.persist(item);
			entityManager.getTransaction().commit();
			entityManager.close();
			return item.getId();
		}
	}

	
	@Override
	public Boolean deleteKnowledgeItem(Long id) throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		if (id != null)	{	
			entityManager.getTransaction().begin();
			KnowledgeItem item = getKnowledgeItemById(entityManager, id);
			entityManager.remove(item);
			entityManager.getTransaction().commit();
			entityManager.close();
			return true;
		}
		entityManager.close();
		return false;
	}
	@Override
	public Boolean checkAccess() throws IllegalArgumentException {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public Boolean insertKnowledgeAttempt(Long id, Integer score)
			throws IllegalArgumentException {
		EntityManager entityManager = emfInstance.createEntityManager();
		KnowledgeAttempt attempt = new KnowledgeAttempt();
		attempt.setParentId(id);
		attempt.setScore(score);
		attempt.setTimestamp(new Date());
		
		entityManager.getTransaction().begin();
		entityManager.persist(attempt);
		entityManager.getTransaction().commit();
		entityManager.close();
		return true;
		}
}
